#include <string.h>

#include "nonos.h"
#include "rc_codec.h"

#define LOGTAG "RC_CODEC"


/// 在脉冲索引表中匹配指定的脉冲
/// @param pwt [in/out]不同种类的脉冲宽度表(即“脉冲索引表”)
/// @param pwtn [in/out]对应脉冲的数量
/// @param pwtc [in/out]总共有多少种不同种类的脉冲宽度(即“脉冲索引表”实际有效值数量)
/// @param pwerr 在进行脉冲宽度分类时，允许的分类误差百分比(单位:1%)
/// @param pulse 待匹配的脉冲宽度(单位:us)
/// @retval >=0 匹配的脉冲索引
/// @retval <0 时表示错误(未匹配，且脉宽索引表满)
static int matchPulse(uint16_t pwt[], uint8_t pwtn[], uint8_t *pwtc, uint8_t pwerr, uint16_t pulse) {
	int i, err;

	// 在当前脉冲索引表中查找
	for(i=0; i < *pwtc; i++) {
		err = (pwt[i] - pulse)*100L/pwt[i];
		if(ABS(err) <= pwerr) {
			// 如果误差在允许范围内，则表示正确匹配，更新脉宽平均值
			pwt[i] = (pwt[i] * pwtn[i] + pulse) / (pwtn[i] + 1);
			pwtn[i]++;
			return i;
		}
	}

	// 没找到，要创建一个新的
	if(*pwtc < CCODE_MAX_PULSE_WIDTH_TYPE) {
		pwt[*pwtc] = pulse;
		pwtn[*pwtc] = 1;
		return (*pwtc)++;
	}

	// 脉宽索引表满，返回错误
	return -1;
}

/// @brief 扫描、统计脉宽种类、宽度平均值、置信度(coefficient)
/// @param pb 脉冲缓冲区
/// @param pwerr 脉宽识别过程中，允许的误差(百分比)
/// @param pic 脉冲索引码
/// @param co [in]当前置信度; [out]更新后的置信度
/// @return 错误码
RcCodecError rc_pulse_index_code_parse(rc_pulse_buffer_t* pb, uint32_t totalWidth, uint8_t pwerr, rc_pulse_index_code_t *pic, uint8_t *co) {
	uint16_t* pulses = pb->pulses;
	uint8_t pwtn[CCODE_MAX_PULSE_WIDTH_TYPE];
	int j, pwti, err=0, maxErr=0;
	uint16_t pwold, pwnew;

	// 长度相同
	pic->plen = pb->plen;

	// 第 1 次扫描：分组、统计
	pic->pwtc = 0;
	for(j=0; j < pic->plen; j++) {
		pwti = matchPulse(pic->pwt, pwtn, &pic->pwtc, pwerr, pulses[j]);
		if(pwti < 0) { return RcCodecError_TOO_MANY_PULSE_TYPE; }
		pic->pwi[j] = pwti;
	}

	// 根据索引，计算置换之后的脉冲总宽度
	uint32_t totalWidth2 = 0;
	for(j=1; j < pic->plen - 1; j++) {
		totalWidth2 += pic->pwt[pic->pwi[j]];
	}
	logd("totalWidth2 = %d\r\n", totalWidth2);
	
	// 根据索引，把“原始脉冲值”换成“统计值”，记录最大误差，计算置换之后的脉冲总宽度
	uint32_t totalWidth3 = 0;
	for(j=1; j < pic->plen - 1; j++) {
		pwnew = pic->pwt[pic->pwi[j]] * totalWidth / totalWidth2; // 修正各脉冲宽度
		pwnew = pwnew * 10335L / 10000;
		pulses[j] = pwnew;
		totalWidth3 += pwnew;
	}
	logd("totalWidth3 = %d\r\n", totalWidth3);

	// 第 2 次扫描：消除初次统计造成的误码
	pic->pwtc = 0;
	for(j=0; j < pic->plen; j++) {
		pwti = matchPulse(pic->pwt, pwtn, &pic->pwtc, pwerr, pulses[j]);
		if(pwti < 0) { return RcCodecError_TOO_MANY_PULSE_TYPE; }
		pic->pwi[j] = pwti;
	}

	// 再次统计最大误差
	for(j=0; j < pic->plen; j++) {
		pwold = pulses[j];
		pwnew = pic->pwt[pic->pwi[j]];

		err = (pwnew - pwold)*100L/pwnew;
		if(maxErr < err) { maxErr = err; }
	}

	*co = 100 - maxErr;
	logd("Total %d index, %d pulses, %d%% coefficient\r\n", pic->pwtc, pic->plen, *co);
	return RcCodecError_OK;
}

RcCodecError rc_pulse_index_code_pack(rc_pulse_index_code_t *pic, uint8_t *data, uint16_t *len) {
	// 计算编码后的数据长度
	int size = ( 1 + pic->pwtc*2 + 1 + pic->plen/2 );
	if(size > *len) { return RcCodecError_BUFFER_OVERFLOW; }

	int i;
	*data = pic->pwtc;									data += 1;				// 脉冲宽度表中元素数量
	memcpy(data, pic->pwt, pic->pwtc*2);				data += pic->pwtc*2;	// 脉冲宽度表数据
	*data = pic->plen;									data += 1;				// 脉冲数量

	// 把索引码压缩存储到缓冲区中(2个索引码占1个字节)
	for(i=0; i < pic->plen/2; i++) {
		*data = ((pic->pwi[2*i+1]<<4) | pic->pwi[2*i]);	data += 1;
	}

	*len = size;
	return RcCodecError_OK;
}

RcCodecError rc_pulse_index_code_unpack(const uint8_t *data, uint16_t len, rc_pulse_index_code_t *pic) {
	if(!data || !len || !pic) { return RcCodecError_BUFFER_UNDERFLOW; }	
	
	// 脉冲宽度表中元素数量
	if(len < 1) { return RcCodecError_BUFFER_UNDERFLOW; }
	pic->pwtc = *data;									data += 1; len -= 1;
	if(pic->pwtc > CCODE_MAX_PULSE_WIDTH_TYPE) { return RcCodecError_TOO_MANY_PULSE_TYPE; }
	
	// 脉冲宽度表数据
	if(len < pic->pwtc*2) { return RcCodecError_BUFFER_UNDERFLOW; }
	memcpy(pic->pwt, data, pic->pwtc*2);				data += pic->pwtc*2; len -= pic->pwtc*2;
	
	// 脉冲数量
	if(len < 1) { return RcCodecError_BUFFER_UNDERFLOW; }
	pic->plen = *data;									data += 1; len -= 1;	
	if(pic->plen > CCODE_MAX_LEN) { return RcCodecError_TOO_MANY_PULSE; }

	// 脉冲索引
	if(len < pic->plen/2) { return RcCodecError_BUFFER_UNDERFLOW; }
	for(int i=0; i < pic->plen/2; i++) {
		uint8_t idx = *data;									data += 1;
		pic->pwi[2*i] = idx & 0x0F;
		pic->pwi[2*i+1] = idx >> 4;
	}
	// 检查索引是否正确
	for(int i=0; i<pic->plen; i++) {
		if(pic->pwi[i] >= pic->pwtc) { return RcCodecError_INVALID_INDEX; }
	}

	return RcCodecError_OK;
}

/*
{
	//
	// 主码及码型识别
	//
	// 统计主码数量
	pic->mctc = 0;
	for(j=0; j<pic->pwtc; j++) {
		// 某个脉宽类型如果统计数量大于 4 个 ，则认为是主码
		if(pwtn[j] > 4) {
			pic->mctc++;
			if(pic->mctc == 1) {
				pic->mcxi = j;
			} else if(pic->mctc == 2) {
				pic->mcyi = j;
			}
		}
	}

	// 通过计算脉宽统计数量的差值，来识别码型
	err = ISTIMES(pwtn[pic->mcxi], pwtn[pic->mcyi]);
	if( err < 110 ) {
		// 如果两个码的数量基本相同，则基本可以肯定是 XY/YX 型
		pic->mcbt = BitType_XY_YX;
	} else if( err > 180 ) {
		// 如果一个码统计数量是另外一个的 180% 以上，则很可能是 XX/XY 型
		pic->mcbt = BitType_XX_XY;
	} else {
		// 难道是 XX/YY 型？
		pic->mcbt = BitType_XX_YY;
	}
}

#define IS_MC(i) 			((i==_mcxi) || (i==_mcyi))

#define IS_XY_YX_BIT0(i, j)	((_mcbt == BitType_XY_YX) && (i==_mcxi) && (j==_mcyi))
#define IS_XY_YX_BIT1(i, j)	((_mcbt == BitType_XY_YX) && (i==_mcyi) && (j==_mcxi))

#define IS_XX_XY_BIT0(i, j)	((_mcbt == BitType_XX_XY) && (i==_mcxi) && (j==_mcxi))
#define IS_XX_XY_BIT1(i, j)	((_mcbt == BitType_XX_XY) && (i==_mcxi) && (j==_mcyi))

#define IS_XX_YY_BIT0(i, j)	((_mcbt == BitType_XX_YY) && (i==_mcxi) && (j==_mcxi))
#define IS_XX_YY_BIT1(i, j)	((_mcbt == BitType_XX_YY) && (i==_mcyi) && (j==_mcyi))

/// 扫描主码
/// @param mcb: 主码开始位置
/// @param bits: 解码出来的bit流
/// 返回：主码脉宽数量
int scanMc(rc_pulse_index_code_t *pic, int mcb, BitStream* bits);

int CPulseIndexCode::scanMc(int mcb, BitStream* bits) {
	int j, a, b;
	// 主码索引开始位置
	uint8_t* pwi = _pwi + mcb;
	// 要扫描的长度
	int len = _len - mcb;
	// 主码脉宽数量
	int mcc = 0;

	for(j=0; j<(len>>1); j++) {
		a = pwi[(j<<1)]; b = pwi[(j<<1)+1];

		if        (IS_XY_YX_BIT0(a, b) || IS_XX_XY_BIT0(a, b) || IS_XX_YY_BIT0(a, b)) {
			mcc += 2; bits->append(0); logchar('0');
		} else if (IS_XY_YX_BIT1(a, b) || IS_XX_XY_BIT1(a, b) || IS_XX_YY_BIT1(a, b)) {
			mcc += 2; bits->append(1); logchar('1');
		} else {
			// 尝试对最后一个 bit 进行特殊处理
			if( IS_MC(a) && (_pwt[b] > 2*(_pwt[_mcxi] + _pwt[_mcyi])) ) {
				int bit = -1;
				if(_mcbt == BitType_XY_YX) {
					bit = (a == _mcxi) ? 0 : 1;
				} else if(_mcbt == BitType_XX_XY) {
					// 这种情况下，认为右脉冲是X/Y中更宽的那个
					bit = (_pwt[_mcxi] > _pwt[_mcyi]) ? 0 : 1;
				} else if(_mcbt == BitType_XX_YY) {
					bit = (a == _mcxi) ? 0 : 1;
				}

				if(bit >= 0) {
					mcc += 1; bits->append(bit); logchar('0'+bit);
				}
			}

			// 结束
			break;
		}
		if(((j+1)&7) == 0) { logchar(' '); }
	}

	log("\r\n");

	return mcc;
}

RcCodecError CPulseIndexCode::packBitCode(uint8_t buff[], uint16_t len) {
	int j;
	/// 主码起始位置(也是头部结束位置)
	int hpwc;
	/// 主码脉宽数量
	int mcc;
	// Bit 缓冲区
	uint8_t bbits[16];
	BitStream bits(bbits, 16*8, 0);
	int pw;

	// 如果主码种类超过2个，则不可能编码成 Bit 码
	if(_mctc > 2) { return RcCodecError_TOO_MANY_MC; }

	//
	// 查找正确的主码起始位置，并进行 bit 编码
	//
	hpwc = -1; mcc = 0;

	for(j=0; j<4; j++) {
		if( IS_MC(_pwi[j]) && (hpwc < 0) ) {
			hpwc = j;
			bits.clear();

			// 尝试扫描并解码数据bits，返回尾码结束位置
			mcc = scanMc(j, &bits);

			if((_len - mcc) > 4) {
				// 如果非主码脉冲个数大于4个，说明有问题！
				// 继续从下一个位置开始对齐查找
				hpwc = -1; mcc = 0;
				continue;
			} else {
				// OK，已经找到了正确的主码起始位置
				break;
			}
		}
	}

	if(j >= 4) {
		// 无法找到正确的 bit 编码方式
		return RcCodecError_UNKNWON_BIT_TYPE;
	}

	//
	// 开始打包
	//
	// 填写头、尾部脉冲数量
	uint8_t tpwc = _len - hpwc - mcc;
	buff[0] = MAKE_BYTE(tpwc, hpwc);					buff += 1;

	// 头部脉冲宽度表
	for(j=0; j<hpwc; j++) {
		pw = _pwt[_pwi[j]];

		// 根据电平，为第一个脉冲添加符号
		if((j == 0) && (_startLevel == 0)) { pw = -pw; }

		*((uint16_t*)buff) = hton16(pw);						buff += 2;
	}

	// 尾部脉冲宽度表
	for(j=tpwc; j>0; j--) {
		pw = _pwt[_pwi[_len-j]];

		// 根据电平，为最后一个脉冲添加符号
		if(j == 1) {
			// 如果是奇数个脉冲，则最后一个脉冲电平与第一个相同
			uint8_t lastLevel = (_len&1)?(_startLevel):(!_startLevel);
			if(lastLevel == 0) {
				pw = -pw;
			}
		}

		*((uint16_t*)buff) = hton16(pw);						buff += 2;
	}

	if(_mcbt == BitType_XY_YX) {
		// '0'脉冲宽度
		*((uint16_t*)buff) = hton16(_pwt[_pwi[_mcxi]]);			buff += 2;
		*((uint16_t*)buff) = hton16(_pwt[_pwi[_mcyi]]);			buff += 2;

		// '1'脉冲宽度
		*((uint16_t*)buff) = hton16(_pwt[_pwi[_mcyi]]);			buff += 2;
		*((uint16_t*)buff) = hton16(_pwt[_pwi[_mcxi]]);			buff += 2;
	} else if(_mcbt == BitType_XX_XY) {
		// '0'脉冲宽度
		*((uint16_t*)buff) = hton16(_pwt[_pwi[_mcxi]]);			buff += 2;
		*((uint16_t*)buff) = hton16(_pwt[_pwi[_mcxi]]);			buff += 2;

		// '1'脉冲宽度
		*((uint16_t*)buff) = hton16(_pwt[_pwi[_mcxi]]);			buff += 2;
		*((uint16_t*)buff) = hton16(_pwt[_pwi[_mcyi]]);			buff += 2;
	} else {
		// '0'脉冲宽度
		*((uint16_t*)buff) = hton16(_pwt[_pwi[_mcxi]]);			buff += 2;
		*((uint16_t*)buff) = hton16(_pwt[_pwi[_mcxi]]);			buff += 2;

		// '1'脉冲宽度
		*((uint16_t*)buff) = hton16(_pwt[_pwi[_mcyi]]);			buff += 2;
		*((uint16_t*)buff) = hton16(_pwt[_pwi[_mcyi]]);			buff += 2;
	}

	// 编码 bit 数
	*buff = bits.bitc;										buff += 1;
	// 编码 bit 数据
	memcpy(buff, bbits, bits.byteLen());

	// 打包的数据总长度
	//len = 1 + (hpwc + tpwc + 2 + 2)*2 + 1 + bits.byteLen();
	
	return RcCodecError_OK;
}

// 头部脉冲数量	尾部脉冲数量	头部脉冲宽度表	尾部脉冲宽度表	'0'脉冲宽度	'1'脉冲宽度	编码 bit 数	编码 bit 数据
// hpwc			tpwc			hpw				tpw				bit0		bit1		bitc		bits
// 低 4 bits		高 4 bits		hpwc*2 byte		tpwc*2 byte		2*2 byte	2*2 byte	1 byte		bitc/8 + ((bitc%8)?1:0)
RcCodecError CPulseIndexCode::unpackBitCode(uint8_t data[], uint16_t dlen) {
	uint8_t hpwc, tpwc, bitc;
	uint16_t *hpw;
	uint8_t* bits;
	int ret, i;
	s16 pw;

	// 取得头、尾部脉冲数量
	hpwc = LO4B(*data); tpwc = HI4B(*data);
	_pwtc = (hpwc + tpwc + 2 + 2);

	if(_pwtc > CCODE_MAX_PULSE_WIDTH_TYPE) {
		return RcCodecError_TOO_MANY_PULSE_TYPE;
	}

	ret = 1 + _pwtc * 2;
	if(dlen < ret+1) {
		return RcCodecError_BUFFER_UNDERFLOW;
	}

	bitc = data[ret];
	bits = data + ret + 1;

	ret = ret + 1 + bitc/8 + ((bitc%8)?1:0);

	if(dlen < ret) {
		return RcCodecError_BUFFER_UNDERFLOW;
	}

	// 开始填写脉冲宽度表
	hpw = (uint16_t*)(data+1);
	for(i=0; i<_pwtc; i++) {
		_pwt[i] = getBeU16(hpw);
		hpw++;
	}
	// 取第一个脉冲的符号来判断是高/低电平
	pw = _pwt[0];
	_startLevel = (pw>0)?1:0;
	// 去掉脉冲的电平符号
	_pwt[0] = ABS(pw);

	// 填写头部脉冲
	_len = 0;
	for(i=0; i<hpwc; i++) {
		_pwi[_len] = i; 				_len++;
	}

	// 填写数据脉冲
	uint8_t ibit0left 	= hpwc + tpwc;
	uint8_t ibit0right 	= ibit0left + 1;
	uint8_t ibit1left 	= ibit0right + 1;
	uint8_t ibit1right 	= ibit1left + 1;
	for(i=0; i<bitc; i++) {
		if(BITn(bits, i) == 0) {
			_pwi[_len] = ibit0left; 	_len++;
			_pwi[_len] = ibit0right; 	_len++;
		} else {
			_pwi[_len] = ibit1left; 	_len++;
			_pwi[_len] = ibit1right; 	_len++;
		}
	}

	// 填写尾部脉冲
	for(i=hpwc; i<(hpwc + tpwc); i++) {
		_pwi[_len] = i; 				_len++;
	}
	//assert(_len == hpwc + bitc*2 + tpwc, "bad len");

	// 取最后一个脉冲的符号来判断是高/低电平？
	pw = _pwt[_pwi[_len-1]];
	//_lastLevel = !_startLevel;	// 最后一个脉冲不一定跟第一个相反！！！
	_lastLevel = (pw>0)?1:0;

	// 去掉脉冲的电平符号
	_pwt[_pwi[_len-1]] = ABS(pw);

	return RcCodecError_OK;
}

int encode2send(CPulseBuffer* pb, uint8_t ifType, uint8_t pwerr, uint8_t coeff) {
	int ret, size;
	CPulseIndexCode pic;
	uint8_t* buff;

	//pb->_startLevel = 0;
	//_rf433tx.send(pb, 20); return 0;
	//_rf315tx.send(pb, 5); return 0;
	//_irtx.send(pb, 50); return 0;

	// 扫描解码
	ret = pic.scan(pb, pwerr);
	if(ret < 0) { return ret; }

	//_rf433tx.send(&pic, 3); return 0;
	//_rf315tx.send(&pic, 3); return 0;
	//_irtx.send(&pic, 50); return 0;

	// 如果扫描后发现接收信号质量太差，则不用传输了
	if(ret < coeff) { return RcCodecError_LOW_COEFF; }

	// 重用脉冲缓冲区
	buff = (uint8_t*)pb->_pulses;
	size = sizeof(pb->_pulses);

	// 先尝试打包成 Bit 码
	ret = pic.packBitCode(buff+3, size-3);
	if(ret > 0) {
		// 打包成功
		// 打印输出编码数据帧
		dumpBin(buff+3, ret, 16, false, false);

		// 填写总帧数、当前帧号
		buff[0] = 1; buff[1] = 0;
		// 填写编码类型
		buff[2] = RcCodeType_BIT | ifType;
		ret += 3;
	} else {
		// 打包成脉冲索引码
		ret = pic.packIndexCode(buff+1, size-1);
		if(ret < 0) { return ret; }

		// 打包成功，填写编码类型
		buff[0] = RcCodeType_PULSE_INDEX | ifType;
		ret++;
	}

	//
	// 发送数据到网关
	//	
	//memcpy(ship2Proxy.params, buff, ret);

	return 0;
}

RcCodecError decode2emit(uint8_t* buff, uint8_t len) {
	CPulseIndexCode pic;

	uint8_t times = *buff;	buff += 1;		// 重复发送的次数
	uint8_t type = *buff;	buff += 1;		// 编码类型

	// 根据编码类型，调用相应的解码程序
	if((type & 0x0F) == RcCodeType_PULSE_INDEX) {
		RcCodecError err = pic.unpackIndexCode(buff, len-2);
		if(err) { return err; }
	}
	else if((type & 0x0F) == RcCodeType_BIT) {
		RcCodecError err = pic.unpackBitCode(buff, len-2);
		if(err) { return err; }
	}
	else if((type & 0x0F) == RcCodeType_HXDIR) {
		// do nothing
	}
	else {
		return RcCodecError_UNKNWON_RCTYPE;
	}


	// 根据编码接口类型，使用对应的遥控接口驱动发送
	if((type & 0xF0) == RcIfType_RF315) {
		//if(_tx315) { _tx315->send(&pic, times); }
	}
	else if((type & 0xF0) == RcIfType_RF433) {
		//if(_tx433) { _tx433->send(&pic, times); }
	}
	else if((type & 0xF0) == RcIfType_IR) {
		//if(_irtx) { _irtx->send(&pic, times); }
	}
	else if((type & 0xF0) == RcIfType_HXDIR) {
		//ByteBuffer bbuf(buff, ret, ret);
		//if(_hxdtx) { _hxdtx->send((IRcCode*)&bbuf, times); }
	}
	else {
		return RcCodecError_UNKNWON_IFTYPE;
	}

	return RcCodecError_OK;
}
*/

uint16_t rc_code_get(RcCodeType codeType, const void *code, uint16_t idx) {
	if(codeType == RcCodeType_RAW) {
		return rc_pulse_buffer_get((rc_pulse_buffer_t*)code, idx);
	} else if(codeType == RcCodeType_PULSE_INDEX) {
		return rc_pulse_index_code_get((rc_pulse_index_code_t*)code, idx);
	} else if(codeType == RcCodeType_BIT) {
		return 0;
	} else {
		return 0;
	}
}

uint16_t rc_code_next(RcCodeType codeType, const void *code) {
	if(codeType == RcCodeType_RAW) {
		return rc_pulse_buffer_next((rc_pulse_buffer_t*)code);
	} else if(codeType == RcCodeType_PULSE_INDEX) {
		return rc_pulse_index_code_next((rc_pulse_index_code_t*)code);
	} else if(codeType == RcCodeType_BIT) {
		return 0;
	} else {
		return 0;
	}
}

void rc_code_dump(RcCodeType codeType, const void *code) {
	uint16_t width = rc_code_get(codeType, code, 0);
	while(width) {
		log("%4d ", width);
		width = rc_code_next(codeType, code);
	}
}


/// @}
